﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace NFinal.Owin
{
    /// <summary>
    /// 从浏览器传过来的请求数据
    /// </summary>
    public class Request
    {
        /// <summary>
        /// 请求头
        /// </summary>
        public IDictionary<string,string[]> headers = null;
        /// <summary>
        /// 请求头中包含的Cookie信息
        /// </summary>
        public IDictionary<string,string> cookies = null;
        /// <summary>
        /// 请求中包含的内容，例如POST请求
        /// </summary>
        public Stream stream = null;
        /// <summary>
        /// 请求方法
        /// </summary>
        public NFinal.MethodType methodType = NFinal.MethodType.NONE;
        /// <summary>
        /// Post请求中包含的文件流
        /// </summary>
        public Dictionary<string, NFinal.HttpFile> files = null;
        /// <summary>
        /// 请求的根路径，例：http://www.x.com
        /// </summary>
        public string requestRoot = null;
        /// <summary>
        /// 请求的绝对路径,例：/Index.html
        /// </summary>
        public string requestPath = null;
        /// <summary>
        /// 请求host中包含的二级域名，例www,bbs,news,admin等
        /// </summary>
        public string subdomain = null;
        /// <summary>
        /// 请求中包含的参数
        /// </summary>
        public NameValueCollection get = new NameValueCollection();
        /// <summary>
        /// owin框架
        /// </summary>
        public IDictionary<string, object> environment = null;
        /// <summary>
        /// QueryString
        /// </summary>
        public string queryString
        {
            get
            {
                return (string)environment["owin.RequestQueryString"];
            }
        }
        /// <summary>
        /// 从Owin中提取所需的请求信息
        /// </summary>
        /// <param name="environment">Owin参数</param>
        public Request(IDictionary<string, object> environment)
        {
            this.environment = environment;
            headers = (IDictionary<string, string[]>)environment["owin.RequestHeaders"];
            cookies = new Dictionary<string, string>();
            if (headers.ContainsKey("Cookie"))
            {
                string[] tempArray = headers["Cookie"][0].Split('&', '=');
                if ((tempArray.Length & 1) == 0)
                {
                    int len = tempArray.Length >> 1;
                    int i = 0;
                    while (i < len)
                    {
                        cookies.Add(tempArray[i << 1], Uri.UnescapeDataString(tempArray[(i << 1) + 1]));
                        i++;
                    }
                }
            }
            stream = (Stream)environment["owin.RequestBody"];
            //请求参数
            requestPath = (string)environment["owin.RequestPathBase"] + (string)environment["owin.RequestPath"];
            //获取二级域名
            string host = headers["Host"][0];
            requestRoot = environment["owin.RequestScheme"] + ":" + host;
            string[] hostName = host.Split('.');
            this.subdomain = hostName.Length == 3 ? hostName[0] : "www";
            //获取POST方法
            string methodTypeTemp = (string)environment["owin.RequestMethod"];
            switch (methodTypeTemp)
            {
                case "POST": methodType = NFinal.MethodType.POST; break;
                case "GET": methodType = NFinal.MethodType.GET; break;
                case "DELETE": methodType = NFinal.MethodType.DELETE; break;
                case "PUT": methodType = NFinal.MethodType.PUT; break;
                case "AJAX": methodType = NFinal.MethodType.AJAX; break;
                default: methodType = NFinal.MethodType.NONE; break;
            }
            //提取内容类型
            if (methodType == NFinal.MethodType.POST)
            {
                NFinal.ContentType contentType = NFinal.ContentType.NONE;
                string contentTypeString = headers["ContentType"][0];
                switch (contentTypeString.Split(';')[0])
                {
                    case "multipart/form-data": contentType = NFinal.ContentType.Multipart_form_data; break;
                    case "text/json":
                    case "application/json": contentType = NFinal.ContentType.Application_json; break;
                    case "application/x-www-form-urlencoded": contentType = NFinal.ContentType.Application_x_www_form_urlencoded; break;
                    case "application/xml":
                    case "text/xml": contentType = NFinal.ContentType.Text_xml; break;
                    default: contentType = NFinal.ContentType.NONE; break;
                }
                //提取form参数
                if (stream != System.IO.Stream.Null)
                {
                    if (contentType == NFinal.ContentType.Application_x_www_form_urlencoded)
                    {
                        System.IO.StreamReader sr = new System.IO.StreamReader(stream);
                        string body = sr.ReadToEnd();
                        sr.Dispose();
                        if (!string.IsNullOrEmpty(body))
                        {
                            string[] formArray = body.Split('&', '=');
                            if (formArray.Length > 1 && (formArray.Length & 1) == 0)
                            {
                                for (int i = 0; i < formArray.Length; i += 2)
                                {
                                    get.Add(formArray[i], NFinal.Utility.UrlDecode(formArray[i + 1]));
                                }
                            }
                        }
                    }
                    //else if (contentType == NFinal.ContentType.Text_xml)
                    //{
                    //    System.IO.StreamReader sr = new System.IO.StreamReader(stream);
                    //    string body = sr.ReadToEnd();
                    //    sr.Dispose();
                    //    if (!string.IsNullOrEmpty(body))
                    //    {
                    //        System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                    //        doc.LoadXml(body);
                    //        if (doc.DocumentElement != null)
                    //        {
                    //            foreach (System.Xml.XmlElement xmlNode in doc.DocumentElement.ChildNodes)
                    //            {
                    //                get.Add(xmlNode.Name, xmlNode.Value);
                    //            }
                    //        }
                    //    }
                    //}
                    else if (contentType == NFinal.ContentType.Application_json)
                    {
                        System.IO.StreamReader sr = new System.IO.StreamReader(stream);
                        string body = sr.ReadToEnd();
                        sr.Dispose();
                        LitJson.JsonReader jr = new LitJson.JsonReader(body);
                        string name = null, value = null;
                        while (jr.Read())
                        {
                            LitJson.JsonToken token = jr.Token;
                            switch (token)
                            {
                                case LitJson.JsonToken.PropertyName:
                                    name = jr.Value.ToString();
                                    break;
                                case LitJson.JsonToken.Boolean:
                                case LitJson.JsonToken.Int:
                                case LitJson.JsonToken.Double:
                                case LitJson.JsonToken.Long:
                                case LitJson.JsonToken.Null:
                                case LitJson.JsonToken.String:
                                    value = jr.Value.ToString();
                                    get.Add(name, value);
                                    break;
                                case LitJson.JsonToken.ArrayStart:
                                    value = LitJson.JsonMapper.ToObject(jr).ToJson();
                                    get.Add(name, value);
                                    break;
                                case LitJson.JsonToken.ObjectStart:
                                    value = LitJson.JsonMapper.ToObject(jr).ToJson();
                                    get.Add(name, value);
                                    break;
                            }
                        }
                        jr.Close();
                    }
                    else if (contentType == NFinal.ContentType.Multipart_form_data)
                    {
                        //multipart/form-data
                        string boundary = NFinal.HttpMultipart.boundaryReg.Match(contentTypeString).Value;
                        var multipart = new NFinal.HttpMultipart(stream, boundary);
                        foreach (var httpMultipartBoundary in multipart.GetBoundaries())
                        {
                            if (string.IsNullOrEmpty(httpMultipartBoundary.Filename))
                            {
                                string name = httpMultipartBoundary.Name;
                                if (!string.IsNullOrEmpty(name))
                                {
                                    string value = new System.IO.StreamReader(httpMultipartBoundary.Value).ReadToEnd();
                                    get.Add(name, value);
                                }
                            }
                            else
                            {
                                files.Add(httpMultipartBoundary.Name, new NFinal.HttpFile(httpMultipartBoundary));
                            }
                        }
                    }
                }
            }
            string queryString = (string)environment["owin.RequestQueryString"];
            //提取URL?后的参数
            if (queryString.Length > 0)
            {
                string[] queryArray = queryString.Split('&', '=');
                if (queryArray.Length > 1 && (queryArray.Length & 1) == 0)
                {
                    for (int i = 0; i < queryArray.Length; i += 2)
                    {
                        get.Add(queryArray[i], NFinal.Utility.UrlDecode(queryArray[i + 1]));
                    }
                }
            }
        }
    }
}
